/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/* 
 * File:   PublicSocket.h
 * Author: Administrator
 *
 * Created on 2017年11月27日, 下午4:20
 */

#ifndef PUBLICSOCKET_H
#    define PUBLICSOCKET_H
#include"PublicIPTool.h"
typedef union _epoll_data_ex{
struct {
uint16_t    fd;  //套接字
uint16_t    port;//端口
//uint32_t    addr;//主机序IPipv6不兼容
}data;
uint64_t    u64;
}epoll_data_ex;
typedef enum _socket_type{
SOCKET_TYPE_ICMP=1,
SOCKET_TYPE_TCP=6,
SOCKET_TYPE_UDP=17    
}socket_type;
#ifdef __MINGW32__
enum EPOLL_EVENTS {
    EPOLLIN = 0x001,
#define EPOLLIN EPOLLIN
    EPOLLPRI = 0x002,
#define EPOLLPRI EPOLLPRI
    EPOLLOUT = 0x004,
#define EPOLLOUT EPOLLOUT
    EPOLLRDNORM = 0x040,
#define EPOLLRDNORM EPOLLRDNORM
    EPOLLRDBAND = 0x080,
#define EPOLLRDBAND EPOLLRDBAND
    EPOLLWRNORM = 0x100,
#define EPOLLWRNORM EPOLLWRNORM
    EPOLLWRBAND = 0x200,
#define EPOLLWRBAND EPOLLWRBAND
    EPOLLMSG = 0x400,
#define EPOLLMSG EPOLLMSG
    EPOLLERR = 0x008,
#define EPOLLERR EPOLLERR
    EPOLLHUP = 0x010,
#define EPOLLHUP EPOLLHUP
    EPOLLONESHOT = (1 << 30),
#define EPOLLONESHOT EPOLLONESHOT
    EPOLLET = (1 << 31)
#define EPOLLET EPOLLET
  };
struct epoll_event{
  uint32_t events;	/* Epoll events */
  epoll_data_ex data;	/* User data variable */
};
#include"PublicNetHead.h"
#else
#include<sys/epoll.h>
//UNIX下SOCKET为INT
#define SOCKET int
#define closesocket close
#define ioctlsocket ioctl
#endif
class CPublicSocket {
    SOCKET m_sock;//PING或UDP或普通链接 
    SOCKET m_sock6;//ipv6
    //普通Connect   
    //1同步，0异步，只有TCP模式才会用到
    //不介意使用,通常都为异步
    int m_sync;
    int m_timeoutms;//接收超时ms
#ifdef __MINGW32__  
    fd_set m_fdset;
    int m_maxevents;
    struct epoll_event*m_events;
#else
    //批量Connect
    int m_epoll;
    int m_maxevents;
    struct epoll_event*m_events;
#endif    
public:
    CPublicSocket();
    ~CPublicSocket();
    //协议UDP，ICMP，默认收发超时ms，源IP,至少为1ms
    //0成功，-1失败
    int  CreateSocket(socket_type protocol,int timeoutms,const char*srcip);
    void CloseSocket();
    //获取套接字IP
    int GetSocketName(char*ip);
    //接收一次数据,返回接受时间戳,fromip至少40字节,ipflag返回ip包类型，4ipv4，6ipv6 
    int Recv(char*buff,int length,char*fromip=NULL,struct timeval*recvtimestamp=NULL,int*ipflag=NULL);
    //发送一次数据到目标IP
    int Send(char*buff,int length,const char*dstip,uint16_t dstport,int ttl=0);
//***********普通Connect*****************    
    //服务器，超时单位s
    //0成功，-1失败
    int Connect(const char*server,uint16_t port,int timeoutms);
    //发送数据，超时毫秒
    int SendTCP(const char*buff,int length,int timeoutms);
    //接收数据，超时毫秒
    int RecvTCP(char*buff,int length,int timeoutms);
    //发送文件
    //文件描述符，位置，剩余大小
    int SendFile(int fd,int64_t*pos,size_t leftsize);    
//**********端口探测相关*****************
    //0成功，1失败
    int EpollCreate(int maxsize);
    //-1失败 0直接连接成功 返回对应FD
    SOCKET EpollConnect(const char*ip,uint16_t port,const char*src);
    //移除套接字
    //fd会close
    int EpollDel(SOCKET fd);
    //等待连接成功的
    //fd要自己close
    struct epoll_event*EpollWait(int timeout,int&events);   
private:
    //套接字是否可用状态,timeout单位s
    //1可用,
    int IsReadEnable(int timeoutms);
    int IsWriteEnable(int timeoutms);
    //同时判断V4和V6
    int IsReadEnableNew(int timeoutms);
    int IsWriteEnableNew(int timeoutms);
};

#endif /* PUBLICSOCKET_H */

